/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#define USING_LOG_PREFIX SQL
#include "sql/ob_dml_stmt_printer.h"
#include "sql/ob_select_stmt_printer.h"
#include "sql/ob_sql_context.h"
#include "sql/resolver/dml/ob_del_upd_stmt.h"
#include "common/ob_smart_call.h"
#include "lib/charset/ob_charset.h"
#include "sql/optimizer/ob_log_plan.h"
#include "sql/monitor/ob_sql_plan.h"
namespace oceanbase
{
using namespace common;
namespace sql
{

ObDMLStmtPrinter::ObDMLStmtPrinter(char *buf, int64_t buf_len, int64_t *pos, const ObDMLStmt *stmt,
                                   ObSchemaGetterGuard *schema_guard,
                                   ObObjPrintParams print_params,
                                   const ParamStore *param_store)
  : buf_(buf),
    buf_len_(buf_len),
    pos_(pos),
    stmt_(stmt),
    is_root_(false),
    schema_guard_(schema_guard),
    print_params_(print_params),
    expr_printer_(buf, buf_len, pos, schema_guard_, print_params_, param_store),
    param_store_(param_store)
{
}

ObDMLStmtPrinter::~ObDMLStmtPrinter()
{
}

void ObDMLStmtPrinter::init(char *buf, int64_t buf_len, int64_t *pos, ObDMLStmt *stmt)
{
  buf_ = buf;
  buf_len_ = buf_len;
  pos_ = pos;
  stmt_ = stmt;
  print_params_.print_with_cte_ = true; // default true
  // force print with cte regardless of the value of print_with_cte_
  // this flag is not final solution, will be optimized later
  print_params_.force_print_cte_ = false;
}

int ObDMLStmtPrinter::print_hint()
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(stmt_) || OB_ISNULL(stmt_->get_query_ctx()) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else {
    const char *hint_begin = "/*+";
    const char *hint_end = " */";
    DATA_PRINTF("%s", hint_begin);
    if (OB_SUCC(ret)) {
      const ObQueryHint &query_hint = stmt_->get_query_ctx()->get_query_hint();
      // just for print hint, ExplainType set as invalid type
      PlanText plan_text;
      plan_text.buf_ = buf_;
      plan_text.buf_len_ = buf_len_;
      plan_text.pos_ = *pos_;
      plan_text.is_oneline_ = true;
      bool ignore_parallel = print_params_.for_dblink_;
      if (OB_FAIL(query_hint.print_stmt_hint(plan_text, *stmt_, is_root_, ignore_parallel))) {
        LOG_WARN("failed to print stmt hint", K(ret));
      } else if (plan_text.pos_ == *pos_) {
        // no hint, roolback buffer!
        *pos_ -= strlen(hint_begin);
      } else {
        *pos_ = plan_text.pos_;
        DATA_PRINTF("%s", hint_end);
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_from(bool need_from)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(stmt_) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else {
    int64_t from_item_size = stmt_->get_from_item_size();
    if (from_item_size > 0) {
      if (need_from) {
        DATA_PRINTF(" from ");
      }
      for (int64_t i = 0; OB_SUCC(ret) && i < from_item_size; ++i) {
        const FromItem &from_item = stmt_->get_from_item(i);
        const TableItem *table_item = NULL;
        if (from_item.is_joined_) {
          table_item = stmt_->get_joined_table(from_item.table_id_);
        } else {
          table_item = stmt_->get_table_item_by_id(from_item.table_id_);
        }
        if (OB_ISNULL(table_item)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("table_item should not be NULL", K(ret));
        } else if (OB_FAIL(print_table(table_item))) {
          LOG_WARN("fail to print table", K(ret), K(*table_item));
        } else {
          DATA_PRINTF(",");
        }
      }
      if (OB_SUCC(ret)) {
        --*pos_;
      }
    } else if (0 != stmt_->get_condition_exprs().count()) {
      // create view v as select 1 from dual where 1;
      DATA_PRINTF(" from DUAL");
    } else if (lib::is_oracle_mode() && 0 == from_item_size) {
      // select 1 from dual
      // in oracle mode
      DATA_PRINTF(" from DUAL");
    }
    if (OB_SUCC(ret) && !print_params_.for_dblink_) {
      if (OB_FAIL(print_semi_join())) {
        LOG_WARN("failed to print semi info", K(ret));
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_table_with_subquery(const TableItem *table_item)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(table_item) ||
      OB_ISNULL(table_item->ref_query_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected null", K(ret));
  } else {
    // force print alias name for select item in generated table. Otherwise,
    // create view v as select 1 from dual where 1 > (select `abs(c1)` from (select abs(c1) from t));
    // Definition of v would be:
    // CREATE VIEW `v` AS select 1 AS `1` from DUAL where (1 > (select `abs(c1)` from ((select abs(`test`.`t`.`c1`) from `test`.`t`)) ))
    // `abs(c1)` would be an unknown column.
    const uint64_t subquery_print_params =
                           PRINT_BRACKET |
                           (stmt_->is_select_stmt() ? FORCE_COL_ALIAS : 0);
    if (OB_FAIL(print_subquery(table_item->ref_query_,
                               subquery_print_params))) {
      LOG_WARN("failed to print subquery", K(ret));
    } else if (!table_item->alias_name_.empty()) {
      PRINT_QUOT_WITH_SPACE;
      DATA_PRINTF("%.*s", LEN_AND_PTR(table_item->alias_name_));
      PRINT_QUOT;
    } else {
      DATA_PRINTF(" ");
      PRINT_TABLE_NAME(print_params_, table_item);
    }
  }
  return ret;
}

int ObDMLStmtPrinter::print_table(const TableItem *table_item,
                                  bool no_print_alias/*default false*/)
{
  int ret = OB_SUCCESS;
  bool is_stack_overflow = false;
  if (OB_FAIL(check_stack_overflow(is_stack_overflow))) {
    LOG_WARN("failed to check stack overflow", K(ret), K(is_stack_overflow));
  } else if (is_stack_overflow) {
    ret = OB_SIZE_OVERFLOW;
    LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow));
  } else if (OB_ISNULL(stmt_) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else {
    switch (table_item->type_) {
    case TableItem::LINK_TABLE: {
        if (OB_FAIL(print_base_table(table_item))) {
          LOG_WARN("failed to print base table", K(ret), K(*table_item));
        } else if (!no_print_alias && !table_item->alias_name_.empty()) {
          DATA_PRINTF(lib::is_oracle_mode() ? " \"%.*s\"" : " `%.*s`",
                      LEN_AND_PTR(table_item->alias_name_));
        }
        break;
      }
    case TableItem::BASE_TABLE: {
        if (OB_FAIL(print_base_table(table_item))) {
          LOG_WARN("failed to print base table", K(ret), K(*table_item));
        } else if (!no_print_alias && !table_item->alias_name_.empty()) {
          DATA_PRINTF(lib::is_oracle_mode() ? " \"%.*s\"" : " `%.*s`",
                      LEN_AND_PTR(table_item->alias_name_));
        }
        break;
      }
    case TableItem::ALIAS_TABLE: {
        if (OB_FAIL(print_base_table(table_item))) {
          LOG_WARN("failed to print base table", K(ret), K(*table_item));
        //table in insert all can't print alias(bug:https://work.aone.alibaba-inc.com/issue/31941210)
        } else if (!no_print_alias) {
          PRINT_QUOT_WITH_SPACE;
          DATA_PRINTF("%.*s", LEN_AND_PTR(table_item->alias_name_));
          PRINT_QUOT;
        }
        break;
      }
    case TableItem::JOINED_TABLE: {
        const JoinedTable *join_table = static_cast<const JoinedTable*>(table_item);
        if (OB_ISNULL(join_table)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("join_table should not be NULL", K(ret));
        } else {
          // left table
          const TableItem *left_table = join_table->left_table_;
          if (OB_ISNULL(left_table)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("left_table should not be NULL", K(ret));
          } else {
            DATA_PRINTF("(");
            if (OB_SUCC(ret)) {
              if (OB_FAIL(SMART_CALL(print_table(left_table)))) {
                LOG_WARN("fail to print left table", K(ret), K(*left_table));
              }
            }
            // join type
            if (OB_SUCC(ret)) {
              // not support cross join and natural join
              ObString type_str("");
              switch (join_table->joined_type_) {
              case FULL_OUTER_JOIN: {
                  type_str = "full join";
                  break;
                }
              case LEFT_OUTER_JOIN: {
                  type_str = "left join";
                  break;
                }
              case RIGHT_OUTER_JOIN: {
                  type_str = "right join";
                  break;
                }
              case INNER_JOIN: {
                  type_str = "join";
                  break;
                }
              case CONNECT_BY_JOIN: {
                  type_str = "connect by join";
                  break;
                }
              default: {
                  ret = OB_ERR_UNEXPECTED;
                  LOG_WARN("unknown join type", K(ret), K(join_table->joined_type_));
                  break;
                }
              }
              DATA_PRINTF(" %.*s ", LEN_AND_PTR(type_str));
            }
            // right table
            if (OB_SUCC(ret)) {
              const TableItem *right_table = join_table->right_table_;
              if (OB_ISNULL(right_table)) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("right_table should not be NULL", K(ret));
              } else if (OB_FAIL(SMART_CALL(print_table(right_table)))) {
                LOG_WARN("fail to print right table", K(ret), K(*right_table));
              } else {
                // join conditions
                const ObIArray<ObRawExpr*> &join_conditions =
                    join_table->join_conditions_;
                int64_t join_conditions_size = join_conditions.count();
                if (join_conditions_size > 0) {
                  DATA_PRINTF(" on ");
                  for (int64_t i = 0; OB_SUCC(ret) && i < join_conditions_size;
                       ++i) {
                    if (OB_FAIL(expr_printer_.do_print(join_conditions.at(i), T_NONE_SCOPE))) {
                      LOG_WARN("fail to print join condition", K(ret));
                    }
                    DATA_PRINTF(" and ");
                  }
                  if (OB_SUCC(ret)) {
                    *pos_ -= 5; // strlen(" and ")
                  }
                } else {
                  DATA_PRINTF(" on 1=1 ");
                }
                DATA_PRINTF(")");
              }
            }
          }
        }
        break;
      }
    case TableItem::GENERATED_TABLE: {
        if (OB_ISNULL(table_item->ref_query_)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("table item ref query is null", K(ret));
        // generated_table cannot appear in view_definition
        // view在resolver阶段被转换为生成表, 需要当做基表处理
        } else if (table_item->is_view_table_ && !print_params_.for_dblink_) {
          PRINT_TABLE_NAME(print_params_, table_item);
          if (OB_SUCC(ret)) {
            if (table_item->alias_name_.length() > 0) {
              DATA_PRINTF(" %.*s", LEN_AND_PTR(table_item->alias_name_));
            }
          }
        } else if (table_item->cte_type_ != TableItem::NOT_CTE && !print_params_.for_dblink_) {
          PRINT_TABLE_NAME(print_params_, table_item);
          if (table_item->alias_name_.length() > 0) {
            DATA_PRINTF(" %.*s", LEN_AND_PTR(table_item->alias_name_));
          }
        } else if (OB_FAIL(print_table_with_subquery(table_item))) {
          LOG_WARN("failed to print table with subquery", K(ret));
        }
        break;
      }
    case TableItem::CTE_TABLE: {
        PRINT_TABLE_NAME(print_params_, table_item);
        if (! table_item->alias_name_.empty()) {
          PRINT_QUOT_WITH_SPACE;
          DATA_PRINTF("%.*s", LEN_AND_PTR(table_item->alias_name_));
          PRINT_QUOT;
        }
        break;
      }
    case TableItem::FUNCTION_TABLE: {
      CK (lib::is_oracle_mode());
      DATA_PRINTF("TABLE(");
      OZ (expr_printer_.do_print(table_item->function_table_expr_, T_FROM_SCOPE));
      DATA_PRINTF(")");
      PRINT_QUOT_WITH_SPACE;
      DATA_PRINTF("%.*s", LEN_AND_PTR(table_item->alias_name_));
      PRINT_QUOT;
      break;
    }
    case TableItem::JSON_TABLE: {
      CK (lib::is_oracle_mode());
      DATA_PRINTF("JSON_TABLE(");
      OZ (expr_printer_.do_print(table_item->json_table_def_->doc_expr_, T_FROM_SCOPE));
      OZ (print_json_table(table_item));
      DATA_PRINTF(")");
      DATA_PRINTF(" %.*s", LEN_AND_PTR(table_item->alias_name_));
      break;
    }
    case TableItem::TEMP_TABLE: {
      if (!print_params_.for_dblink_) {
        PRINT_TABLE_NAME(print_params_, table_item);
        if (!table_item->alias_name_.empty()) {
          PRINT_QUOT_WITH_SPACE;
          DATA_PRINTF("%.*s", LEN_AND_PTR(table_item->alias_name_));
          PRINT_QUOT;
        }
      } else if (OB_FAIL(print_table_with_subquery(table_item))) {
        LOG_WARN("failed to print table with subquery", K(ret));
      }
      break;
    }
    default: {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unknown table type", K(ret), K(table_item->type_));
        break;
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_json_return_type(int64_t value, ObDataType data_type)
{
  int ret = OB_SUCCESS;

  ParseNode parse_node;
  parse_node.value_ = value;

  int16_t cast_type = parse_node.int16_values_[OB_NODE_CAST_TYPE_IDX];
  const ObLengthSemantics length_semantics = data_type.get_length_semantics();
  const ObScale scale = data_type.get_scale();

  switch (cast_type) {
    case T_CHAR: {
      int16_t collation = parse_node.int16_values_[OB_NODE_CAST_COLL_IDX];
      int32_t len = parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX];
      DATA_PRINTF("char(%d %s)", len, get_length_semantics_str(length_semantics));
      break;
    }
    case T_VARCHAR: {
      int16_t collation = parse_node.int16_values_[OB_NODE_CAST_COLL_IDX];
      int32_t len = parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX];
      const int32_t DEFAULT_VARCHAR_LEN = 4000;
      if (BINARY_COLLATION == collation) {
        DATA_PRINTF("varbinary(%d)", len);
      } else {
        // CHARACTER
        if (len == DEFAULT_VARCHAR_LEN) {
          break;
        } else if (length_semantics == LS_BYTE && len == -1) {
          DATA_PRINTF(" VARCHAR2");
          break;
        } else {
          DATA_PRINTF("varchar2(%d %s)", len, get_length_semantics_str(length_semantics));
        }
      }
      break;
    }
    case T_NVARCHAR2: {
      DATA_PRINTF("nvarchar2(%d)", parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX]);
      break;
    }
    case T_NCHAR: {
      DATA_PRINTF("nchar(%d)", parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX]);
      break;
    }
    case T_DATETIME: {
      //oracle mode treate date as datetime
      DATA_PRINTF("date");
      break;
    }
    case T_DATE: {
      DATA_PRINTF("date");
      break;
    }
    case T_TIME: {
      int16_t scale = parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX];
      if (scale >= 0) {
        DATA_PRINTF("time(%d)", scale);
      } else {
        DATA_PRINTF("time");
      }
      break;
    }
    case T_NUMBER: {
      int16_t precision = parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX];
      int16_t scale = parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX];
      DATA_PRINTF("number(%d,%d)", precision, scale);
      break;
    }
    case T_NUMBER_FLOAT: {
      int16_t precision = parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX];
      DATA_PRINTF("float(%d)", precision);
      break;
    }
    case T_TINYINT:
    case T_SMALLINT:
    case T_MEDIUMINT:
    case T_INT32:
    case T_INT: {
      DATA_PRINTF("signed");
      break;
    }
    case T_UTINYINT:
    case T_USMALLINT:
    case T_UMEDIUMINT:
    case T_UINT32:
    case T_UINT64: {
      DATA_PRINTF("unsigned");
      break;
    }
    case T_INTERVAL_YM: {
      int year_scale = ObIntervalScaleUtil::ob_scale_to_interval_ym_year_scale(static_cast<int8_t>(scale));
      DATA_PRINTF("interval year(%d) to month", year_scale);
      break;
    }
    case T_INTERVAL_DS: {
      int day_scale = ObIntervalScaleUtil::ob_scale_to_interval_ds_day_scale(static_cast<int8_t>(scale));
      int fs_scale = ObIntervalScaleUtil::ob_scale_to_interval_ds_second_scale(static_cast<int8_t>(scale));
      DATA_PRINTF("interval day(%d) to second(%d)", day_scale, fs_scale);
      break;
    }
    case T_TIMESTAMP_TZ: {
      int16_t scale = parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX];
      if (scale >= 0) {
        DATA_PRINTF("timestamp(%d) with time zone", scale);
      } else {
        DATA_PRINTF("timestamp with time zone");
      }
      break;
    }
    case T_TIMESTAMP_LTZ: {
      int16_t scale = parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX];
      if (scale >= 0) {
        DATA_PRINTF("timestamp(%d) with local time zone", scale);
      } else {
        DATA_PRINTF("timestamp with local time zone");
      }
      break;
    }
    case T_TIMESTAMP_NANO: {
      int16_t scale = parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX];
      if (scale >= 0) {
        DATA_PRINTF("timestamp(%d)", scale);
      } else {
        DATA_PRINTF("timestamp");
      }
      break;
    }
    case T_RAW: {
      int32_t len = parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX];
      DATA_PRINTF("raw(%d)", len);
      break;
    }
    case T_FLOAT: {
      const char *type_str = lib::is_oracle_mode() ? "binary_float" : "float";
      DATA_PRINTF("%s", type_str);
      break;
    }
    case T_DOUBLE: {
      const char *type_str = lib::is_oracle_mode() ? "binary_double" : "double";
      DATA_PRINTF("%s", type_str);
      break;
    }
    case T_UROWID: {
      DATA_PRINTF("urowid(%d)", parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX]);
      break;
    }
    case T_LOB: {
      int16_t collation = parse_node.int16_values_[OB_NODE_CAST_COLL_IDX];
      if (BINARY_COLLATION == collation) {
        DATA_PRINTF("blob");
      } else {
        DATA_PRINTF("clob");
      }
      break;
    }
    case T_JSON: {
      DATA_PRINTF("json");
      break;
    }
    case T_LONGTEXT: {
      int16_t collation = parse_node.int16_values_[OB_NODE_CAST_COLL_IDX];
      if (BINARY_COLLATION == collation) {
        DATA_PRINTF("blob");
      } else {
        DATA_PRINTF("clob");
      }
      break;
    }
    default: {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unknown cast type", K(ret), K(cast_type));
      break;
    }
  } // end switch
  return ret;
}

int ObDMLStmtPrinter::get_json_table_column_if_exists(int32_t id, ObDmlJtColDef* root, ObDmlJtColDef*& col)
{
  INIT_SUCC(ret);
  common::ObArray<ObDmlJtColDef*> col_stack;
  if (OB_FAIL(col_stack.push_back(root))) {
    LOG_WARN("fail to store col node tmp", K(ret));
  }

  bool exists = false;

  while (OB_SUCC(ret) && !exists && col_stack.count() > 0) {
    ObDmlJtColDef* cur_col = col_stack.at(col_stack.count() - 1);
    if (OB_ISNULL(cur_col)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("current column info is null", K(ret));
    } else if (cur_col->col_base_info_.id_ == id) {
      exists = true;
      col = cur_col;
    } else if (cur_col->col_base_info_.parent_id_ < 0
               || cur_col->col_base_info_.col_type_ == static_cast<int32_t>(NESTED_COL_TYPE)) {
      col_stack.remove(col_stack.count() - 1);
      for (size_t i = 0; !exists && i < cur_col->nested_cols_.count(); ++i) {
        ObDmlJtColDef* nest_col = cur_col->nested_cols_.at(i);
        if (OB_ISNULL(nest_col)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("current column info is null", K(ret));
        } else if (nest_col->col_base_info_.id_ == id) {
          exists = true;
          col = nest_col;
        } else if (nest_col->col_base_info_.col_type_ == static_cast<int32_t>(NESTED_COL_TYPE)
                  && OB_FAIL(col_stack.push_back(nest_col))) {
          LOG_WARN("fail to store col node tmp", K(ret));
        }
      }
    }
  }

  if (OB_SUCC(ret) && !exists) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("fail to find col node", K(ret));
  }
  return ret;
}

int ObDMLStmtPrinter::build_json_table_nested_tree(const TableItem* table_item, ObIAllocator* allocator, ObDmlJtColDef*& root)
{
  int ret = OB_SUCCESS;
  const ObIArray<ObJtColBaseInfo*>& plain_def = table_item->json_table_def_->all_cols_;

  for (size_t i = 0; OB_SUCC(ret) && i < plain_def.count(); ++i) {
    const ObJtColBaseInfo& info = *plain_def.at(i);
    ObDmlJtColDef* col_def = static_cast<ObDmlJtColDef*>(allocator->alloc(sizeof(ObDmlJtColDef)));
    if (OB_ISNULL(col_def)) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_WARN("fail to allocate col node", K(ret));
    } else {
      col_def = new (col_def) ObDmlJtColDef();
      col_def->col_base_info_.assign(info);

      if (info.col_type_ != NESTED_COL_TYPE) {
        ColumnItem* col_item = stmt_->get_column_item_by_id(table_item->table_id_, info.output_column_idx_);
        if (OB_ISNULL(col_item)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("fail to get column item", K(ret), K(info.output_column_idx_));
        } else {
          col_def->error_expr_ = col_item->default_value_expr_;
          col_def->empty_expr_ = col_item->default_empty_expr_;
        }
      }
    }

    if (OB_SUCC(ret)) {
      ObDmlJtColDef* parent = nullptr;
      if (info.parent_id_ < 0) {
        root = col_def;
      } else if (OB_FAIL(get_json_table_column_if_exists(info.parent_id_, root, parent))) {
        LOG_WARN("fail to find col node parent", K(ret), K(info.parent_id_));
      } else if (info.col_type_ == static_cast<int32_t>(NESTED_COL_TYPE)) {
        if (OB_FAIL(parent->nested_cols_.push_back(col_def))) {
          LOG_WARN("fail to store col node", K(ret), K(parent->nested_cols_.count()));
        }
      } else if (OB_FAIL(parent->regular_cols_.push_back(col_def))) {
        LOG_WARN("fail to store col node", K(ret), K(parent->nested_cols_.count()));
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_json_table_nested_column(const TableItem *table_item, const ObDmlJtColDef& col_def)
{
  int ret = OB_SUCCESS;
  ObJsonTableDef* tbl_def  = table_item->json_table_def_;

  bool has_reg_column = false;
  for (size_t i = 0; OB_SUCC(ret) && i < col_def.regular_cols_.count(); ++i) {
    has_reg_column = true;
    ObDmlJtColDef* cur_def = col_def.regular_cols_.at(i);
    if (OB_ISNULL(cur_def)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("current column info is null", K(ret));
    } else {
      const ObJtColBaseInfo& col_info = col_def.regular_cols_.at(i)->col_base_info_;
      if (i > 0) {
        DATA_PRINTF(", ");
      }
      DATA_PRINTF("%.*s ", LEN_AND_PTR(col_info.col_name_));
      if (OB_FAIL(ret)) {
      } else if (col_info.col_type_ == static_cast<int32_t>(COL_TYPE_ORDINALITY)) {
        DATA_PRINTF(" for ordinality");
      } else if (col_info.col_type_ == static_cast<int32_t>(COL_TYPE_EXISTS)) {
        // to print returning type
        OZ (print_json_return_type(col_info.res_type_, col_info.data_type_));
        DATA_PRINTF(" exists");
        if (OB_SUCC(ret) && col_info.path_.length() > 0) {
          DATA_PRINTF(" path \'%.*s\'", LEN_AND_PTR(col_info.path_));
        }
        if (OB_FAIL(ret)) {
        } else if (col_info.on_empty_ == 0) {
          DATA_PRINTF(" false on empty");
        } else if (col_info.on_empty_ == 1) {
          DATA_PRINTF(" true on empty");
        } else if (col_info.on_empty_ == 2) {
          DATA_PRINTF(" error on empty");
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_error_ == 0) {
          DATA_PRINTF(" false on error");
        } else if (col_info.on_error_ == 1) {
          DATA_PRINTF(" true on error");
        } else if (col_info.on_error_ == 2) {
          DATA_PRINTF(" error on error");
        }
      } else if (col_info.col_type_ == static_cast<int32_t>(COL_TYPE_QUERY)) {
        // to print returning type
        OZ (print_json_return_type(col_info.res_type_, col_info.data_type_));
        DATA_PRINTF(" format json");
        if (OB_FAIL(ret)) {
        } else if (col_info.allow_scalar_ == 0) {
          DATA_PRINTF(" allow scalars");
        } else if (col_info.allow_scalar_ == 1) {
          DATA_PRINTF(" disallow scalars");
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.wrapper_ == 0) {
          DATA_PRINTF(" without wrapper");
        } else if (col_info.wrapper_ == 1) {
          DATA_PRINTF(" without array wrapper");
        } else if (col_info.wrapper_ == 2) {
          DATA_PRINTF(" with wrapper");
        } else if (col_info.wrapper_ == 3) {
          DATA_PRINTF(" with array wrapper");
        } else if (col_info.wrapper_ == 4) {
          DATA_PRINTF(" with unconditional wrapper");
        } else if (col_info.wrapper_ == 5) {
          DATA_PRINTF(" with conditional wrapper");
        } else if (col_info.wrapper_ == 6) {
          DATA_PRINTF(" with unconditional array wrapper");
        } else if (col_info.wrapper_ == 7) {
          DATA_PRINTF(" with conditional array wrapper");
        }

        if (OB_SUCC(ret) && col_info.path_.length() > 0) {
          DATA_PRINTF(" path \'%.*s\'", LEN_AND_PTR(col_info.path_));
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_empty_ == 0) {
          DATA_PRINTF(" error on empty" );
        } else if (col_info.on_empty_ == 1) {
          DATA_PRINTF(" null on empty" );
        } else if (col_info.on_empty_ == 2) {
          DATA_PRINTF(" empty on empty" );
        } else if (col_info.on_empty_ == 3) {
          DATA_PRINTF(" empty array on empty" );
        } else if (col_info.on_empty_ == 4) {
          DATA_PRINTF(" empty object on empty" );
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_error_ == 0) {
          DATA_PRINTF(" error on error" );
        } else if (col_info.on_error_ == 1) {
          DATA_PRINTF(" null on error" );
        } else if (col_info.on_error_ == 2) {
          DATA_PRINTF(" empty on error" );
        } else if (col_info.on_error_ == 3) {
          DATA_PRINTF(" empty array on error" );
        } else if (col_info.on_error_ == 4) {
          DATA_PRINTF(" empty object on error" );
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_mismatch_ == 0) {
          DATA_PRINTF(" error on mismatch" );
        } else if (col_info.on_mismatch_ == 1) {
          DATA_PRINTF(" null on mismatch" );
        }
      } else if (col_info.col_type_ == static_cast<int32_t>(COL_TYPE_VALUE)) {
        OZ (print_json_return_type(col_info.res_type_, col_info.data_type_));
        if (col_info.truncate_) {
          DATA_PRINTF(" truncate" );
        }

        if (OB_SUCC(ret) && col_info.path_.length() > 0) {
          DATA_PRINTF(" path \'%.*s\'", LEN_AND_PTR(col_info.path_));
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_empty_ == 0) {
          DATA_PRINTF(" error on empty");
        } else if (col_info.on_empty_ == 1) {
          DATA_PRINTF(" null on empty");
        } else if (col_info.on_empty_ == 2) {
          DATA_PRINTF(" default ");
          if (OB_SUCC(ret)
              && OB_FAIL(expr_printer_.do_print(cur_def->empty_expr_, T_NONE_SCOPE))) {
            LOG_WARN("fail to print default value col", K(ret));
          }
          DATA_PRINTF(" on empty");
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_error_ == 0) {
          DATA_PRINTF(" error on error");
        } else if (col_info.on_error_ == 1) {
          DATA_PRINTF(" null on error");
        } else if (col_info.on_error_ == 2) {
          DATA_PRINTF(" default ");
          if (OB_SUCC(ret)
              && OB_FAIL(expr_printer_.do_print(cur_def->error_expr_, T_NONE_SCOPE))) {
            LOG_WARN("fail to print default value col", K(ret));
          }
          DATA_PRINTF(" on error");
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_mismatch_ == 0) {
          DATA_PRINTF(" error on mismatch");
        } else if (col_info.on_mismatch_ == 1) {
          DATA_PRINTF(" null on mismatch");
        } else if (col_info.on_mismatch_ == 2) {
          DATA_PRINTF(" ignore on mismatch");
        }

        if (OB_FAIL(ret)) {
        } else if (col_info.on_mismatch_type_ == 0) {
          DATA_PRINTF(" (missing data)");
        } else if (col_info.on_mismatch_type_ == 1) {
          DATA_PRINTF(" (extra data)");
        } else if (col_info.on_mismatch_type_ == 2) {
          DATA_PRINTF(" (type error)");
        }
      }
    }
  }

  for (size_t i = 0; OB_SUCC(ret) && i < col_def.nested_cols_.count(); ++i) {
    const ObJtColBaseInfo& col_info = col_def.nested_cols_.at(i)->col_base_info_;
    if (i > 0 || has_reg_column) {
      DATA_PRINTF(",");
    }

    DATA_PRINTF(" nested path \'%.*s\' columns(", LEN_AND_PTR(col_info.path_));
    OZ (print_json_table_nested_column(table_item, *col_def.nested_cols_.at(i)));
    DATA_PRINTF(")");
  }

  return ret;
}

int ObDMLStmtPrinter::print_json_table(const TableItem *table_item)
{
  int ret = OB_SUCCESS;
  ObJsonTableDef* tbl_def  = table_item->json_table_def_;

  ObArenaAllocator alloc;
  ObDmlJtColDef* root_def = nullptr;
  if (OB_SUCC(ret) && OB_FAIL(build_json_table_nested_tree(table_item, &alloc, root_def))) {
    LOG_WARN("fail to build column tree.", K(ret));
  } else if (root_def->col_base_info_.path_.length() > 0) {
    DATA_PRINTF(" , \'%.*s\'", LEN_AND_PTR(root_def->col_base_info_.path_));
  }

  if (OB_SUCC(ret)) {
    if (root_def->col_base_info_.on_empty_ == 0) {
      DATA_PRINTF(" error on empty");
    } else if (root_def->col_base_info_.on_empty_ == 1) {
      DATA_PRINTF(" null on empty");
    } else if (root_def->col_base_info_.on_empty_ == 2) {
      DATA_PRINTF(" default ");
      if (OB_FAIL(expr_printer_.do_print(root_def->empty_expr_, T_NONE_SCOPE))) {
        LOG_WARN("fail to print where expr", K(ret));
      }
      DATA_PRINTF(" on empty");
    }

    if (OB_FAIL(ret)) {
    } else if (root_def->col_base_info_.on_error_ == 0) {
      DATA_PRINTF(" error on error");
    } else if (root_def->col_base_info_.on_error_ == 1) {
      DATA_PRINTF(" null on error");
    } else if (root_def->col_base_info_.on_error_ == 2) {
      DATA_PRINTF(" default ");
      if (OB_SUCC(ret) && OB_FAIL(expr_printer_.do_print(root_def->error_expr_, T_NONE_SCOPE))) {
        LOG_WARN("fail to print default expr", K(ret));
      }
      DATA_PRINTF(" on error");
    }
  }

  DATA_PRINTF(" columns (");
  OZ (print_json_table_nested_column(table_item, *root_def));
  DATA_PRINTF(" )");

  return ret;
}

int ObDMLStmtPrinter::print_base_table(const TableItem *table_item)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(stmt_) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else if (OB_ISNULL(table_item)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("table_item should not be NULL", K(ret));
  } else if (TableItem::BASE_TABLE != table_item->type_
      && TableItem::ALIAS_TABLE != table_item->type_
      && TableItem::LINK_TABLE != table_item->type_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("table_type should be BASE_TABLE or ALIAS_TABLE or LINK_TABLE", K(ret),
             K(table_item->type_));
  } else {
    PRINT_TABLE_NAME(print_params_, table_item);
    if (OB_SUCC(ret)) {
      // partition
      if (!table_item->access_all_part()) {
        const ObIArray<ObString> &part_names = table_item->part_names_;
        DATA_PRINTF(" partition(");
        for (int64_t i = 0; OB_SUCC(ret) && i < part_names.count(); ++i) {
          DATA_PRINTF("%.*s,", LEN_AND_PTR(part_names.at(i)));
        }
        if (OB_SUCC(ret)) {
          --*pos_;
          DATA_PRINTF(")");
        }
      }
      // flashback query
      if (OB_SUCC(ret)) {
        if (OB_NOT_NULL(table_item->flashback_query_expr_)) {
          if (table_item->flashback_query_type_ == TableItem::USING_TIMESTAMP) {
            DATA_PRINTF(" as of timestamp "); 
            if (OB_FAIL(expr_printer_.do_print(table_item->flashback_query_expr_, T_NONE_SCOPE))) {
              LOG_WARN("fail to print where expr", K(ret));
            }
          } else if (table_item->flashback_query_type_ == TableItem::USING_SCN) {
            if (lib::is_oracle_mode()) {
              DATA_PRINTF(" as of scn "); 
            } else {
              DATA_PRINTF(" as of snapshot "); 
            }
            if (OB_FAIL(expr_printer_.do_print(table_item->flashback_query_expr_, T_NONE_SCOPE))) {
              LOG_WARN("fail to print where expr", K(ret));
            }
          } else {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("get unexpected type", K(ret), K(table_item->flashback_query_type_));
          }
        }
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_semi_join()
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(stmt_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpect null stmt", K(ret));
  }
  for (int i = 0; OB_SUCC(ret) && i < stmt_->get_semi_info_size(); ++i) {
    SemiInfo *semi_info = stmt_->get_semi_infos().at(i);
    const TableItem *right_table = NULL;
    if (OB_ISNULL(semi_info)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unexpect null semi info", K(ret));
    } else if (OB_ISNULL(right_table = stmt_->get_table_item_by_id(semi_info->right_table_id_))) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unexpect null table item", K(ret));
    } else {
      DATA_PRINTF(", ");
      // join type
      ObString type_str("");
      switch (semi_info->join_type_) {
      case LEFT_SEMI_JOIN: {
          type_str = "left semi join";
          break;
        }
      case RIGHT_SEMI_JOIN: {
          type_str = "right semi join";
          break;
        }
      case LEFT_ANTI_JOIN: {
          type_str = "left anti join";
          break;
        }
      case RIGHT_ANTI_JOIN: {
          type_str = "right anti join";
          break;
        }
      default: {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unknown join type", K(ret));
          break;
        }
      }
      DATA_PRINTF(" %.*s ", LEN_AND_PTR(type_str));
      // right table
      if (OB_SUCC(ret)) {
        if (OB_FAIL(print_table(right_table))) {
          LOG_WARN("fail to print right table", K(ret), K(*right_table));
        } else {
          // join conditions
          const ObIArray<ObRawExpr*> &join_conditions = semi_info->semi_conditions_;
          int64_t join_conditions_size = join_conditions.count();
          if (join_conditions_size > 0) {
            DATA_PRINTF(" on ");
            for (int64_t i = 0; OB_SUCC(ret) && i < join_conditions_size; ++i) {
              if (OB_FAIL(expr_printer_.do_print(join_conditions.at(i), T_NONE_SCOPE))) {
                LOG_WARN("fail to print join condition", K(ret));
              }
              DATA_PRINTF(" and ");
            }
            if (OB_SUCC(ret)) {
              *pos_ -= 5; // strlen(" and ")
            }
          } else {
            DATA_PRINTF(" on 1=1 ");
          }
        }
      }
    }
  }
  return ret;
}

int ObDMLStmtPrinter::print_semi_info_to_subquery()
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(stmt_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpect null stmt", K(ret));
  }
  for (int i = 0; OB_SUCC(ret) && i < stmt_->get_semi_info_size(); ++i) {
    SemiInfo *semi_info = stmt_->get_semi_infos().at(i);
    const TableItem *right_table = NULL;
    if (OB_ISNULL(semi_info)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unexpect null semi info", K(ret));
    } else if (OB_ISNULL(right_table = stmt_->get_table_item_by_id(semi_info->right_table_id_))) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unexpect null table item", K(ret));
    } else {
      DATA_PRINTF(" ");
      // join type
      ObString type_str("");
      switch (semi_info->join_type_) {
      case LEFT_SEMI_JOIN: {
          type_str = "exists";
          break;
        }
      case LEFT_ANTI_JOIN: {
          type_str = "not exists";
          break;
        }
      default: {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unknown join type", K(ret));
          break;
        }
      }
      DATA_PRINTF("%.*s(select 1 from ", LEN_AND_PTR(type_str));
      // right table
      if (OB_SUCC(ret)) {
        if (OB_FAIL(print_table(right_table))) {
          LOG_WARN("fail to print right table", K(ret), K(*right_table));
        } else {
          // join conditions
          const ObIArray<ObRawExpr*> &join_conditions = semi_info->semi_conditions_;
          int64_t join_conditions_size = join_conditions.count();
          if (join_conditions_size > 0) {
            DATA_PRINTF(" where ");
            for (int64_t i = 0; OB_SUCC(ret) && i < join_conditions_size; ++i) {
              if (OB_FAIL(expr_printer_.do_print(join_conditions.at(i), T_NONE_SCOPE))) {
                LOG_WARN("fail to print join condition", K(ret));
              }
              DATA_PRINTF(" and ");
            }
            if (OB_SUCC(ret)) {
              *pos_ -= 5; // strlen(" and ")
            }
          }
        }
      }
      DATA_PRINTF(") and ");
    }
  }
  if (OB_SUCC(ret) && stmt_->get_semi_info_size() > 0) {
    *pos_ -= 5; // strlen(" and ")
  }
  return ret;
}

int ObDMLStmtPrinter::print_where()
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(stmt_) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else {
    const ObIArray<ObRawExpr*> &condition_exprs = stmt_->get_condition_exprs();
    int64_t condition_exprs_size = condition_exprs.count();
    if (condition_exprs_size > 0) {
      DATA_PRINTF(" where ");
      for (int64_t i = 0; OB_SUCC(ret) && i < condition_exprs_size; ++i) {
        if (OB_FAIL(expr_printer_.do_print(condition_exprs.at(i), T_WHERE_SCOPE))) {
          LOG_WARN("fail to print where expr", K(ret));
        }
        DATA_PRINTF(" and ");
      }
      if (OB_SUCC(ret)) {
        *pos_ -= 5; // strlen(" and ")
      }
    }
    if (print_params_.for_dblink_) {
      if (condition_exprs_size == 0 && stmt_->get_semi_info_size() > 0) {
        DATA_PRINTF(" where ");
      } else if (condition_exprs_size > 0 && stmt_->get_semi_info_size() > 0) {
        DATA_PRINTF(" and ");
      }
      if (OB_FAIL(print_semi_info_to_subquery())) {
        LOG_WARN("failed to print semi info to subquery", K(ret));
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_quote_for_const(ObRawExpr* expr, bool &print_quote)
{
  int ret = OB_SUCCESS;
  print_quote = false;
  if (OB_ISNULL(expr)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected null", K(ret));
  } else if (expr->is_const_or_param_expr()) {
    print_quote = expr->get_result_type().is_numeric_type();
  }
  return ret;
}

int ObDMLStmtPrinter::print_expr_except_const_number(ObRawExpr* expr, ObStmtScope scope)
{
  int ret = OB_SUCCESS;
  bool print_quote = false;
  if (OB_FAIL(print_quote_for_const(expr, print_quote))) {
    LOG_WARN("failed to check is const number", K(ret));
  } else if (print_quote) {
    DATA_PRINTF("'");
  }
  if (OB_FAIL(ret)) {
  } else if (OB_FAIL(expr_printer_.do_print(expr, scope))) {
    LOG_WARN("fail to print order by expr", K(ret));
  } else if (print_quote) {
    DATA_PRINTF("'");
  }
  return ret;
}

int ObDMLStmtPrinter::print_order_by()
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(stmt_) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else {
    ObArenaAllocator alloc;
    ObConstRawExpr expr(alloc);
    int64_t order_item_size = stmt_->get_order_item_size();
    if (order_item_size > 0) {
      DATA_PRINTF(" order by ");
      for (int64_t i = 0; OB_SUCC(ret) && i < order_item_size; ++i) {
        const OrderItem &order_item = stmt_->get_order_item(i);
        if (OB_FAIL(print_expr_except_const_number(order_item.expr_, T_ORDER_SCOPE))) {
          LOG_WARN("fail to print order by expr", K(ret));
        } else if (lib::is_mysql_mode()) {
          if (is_descending_direction(order_item.order_type_)) {
            DATA_PRINTF("desc");
          }
        } else if (order_item.order_type_ == NULLS_FIRST_ASC) {
          DATA_PRINTF("asc nulls first");
        } else if (order_item.order_type_ == NULLS_LAST_ASC) {//use default value
          /*do nothing*/
        } else if (order_item.order_type_ == NULLS_FIRST_DESC) {//use default value
          DATA_PRINTF("desc");
        } else if (order_item.order_type_ == NULLS_LAST_DESC) {
          DATA_PRINTF("desc nulls last");
        } else {/*do nothing*/}
        DATA_PRINTF(",");
      }
      if (OB_SUCC(ret)) {
        --*pos_;
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_limit()
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(stmt_) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else if (stmt_->has_fetch() || is_oracle_mode()) {
    /*有fetch,说明是oracle mode下的fetch填充的limit,这里不应该打印 */
  } else {
    if (NULL != stmt_->get_offset_expr() || NULL != stmt_->get_limit_expr()) {
      DATA_PRINTF(" limit ");
    }
    // offset
    if (OB_SUCC(ret)) {
      if (NULL != stmt_->get_offset_expr()) {
        if (OB_FAIL(expr_printer_.do_print(stmt_->get_offset_expr(), T_NONE_SCOPE))) {
          LOG_WARN("fail to print order offset expr", K(ret));
        }
        DATA_PRINTF(",");
      }
    }
    // limit
    if (OB_SUCC(ret)) {
      if (NULL != stmt_->get_limit_expr()) {
        if (OB_FAIL(expr_printer_.do_print(stmt_->get_limit_expr(), T_NONE_SCOPE))) {
          LOG_WARN("fail to print order limit expr", K(ret));
        }
      }
    }
  }

  return ret;
}

int ObDMLStmtPrinter::print_fetch()
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(stmt_) || OB_ISNULL(buf_) || OB_ISNULL(pos_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt_ is NULL or buf_ is NULL or pos_ is NULL", K(ret));
  } else if (stmt_->has_fetch() || (stmt_->has_limit() && is_oracle_mode())) {
    // offset
    if (OB_SUCC(ret)) {
      if (NULL != stmt_->get_offset_expr()) {
        DATA_PRINTF(" offset ");
        if (OB_FAIL(expr_printer_.do_print(stmt_->get_offset_expr(), T_NONE_SCOPE))) {
          LOG_WARN("fail to print order offset expr", K(ret));
        }
        DATA_PRINTF(" rows");
      }
    }
    // fetch
    if (OB_SUCC(ret)) {
      if (NULL != stmt_->get_limit_expr()) {
        DATA_PRINTF(" fetch next ");
        if (OB_FAIL(expr_printer_.do_print(stmt_->get_limit_expr(), T_NONE_SCOPE))) {
          LOG_WARN("fail to print order limit expr", K(ret));
        }
        DATA_PRINTF(" rows");
      }
    }
    //fetch percent
    if (OB_SUCC(ret)) {
      if (NULL != stmt_->get_limit_percent_expr()) {
        DATA_PRINTF(" fetch next ");
        if (OB_FAIL(expr_printer_.do_print(stmt_->get_limit_percent_expr(), T_NONE_SCOPE))) {
          LOG_WARN("fail to print order limit expr", K(ret));
        }
        DATA_PRINTF(" percent rows");
      }
    }
    //fetch only/with ties
    if (OB_SUCC(ret) &&
        (NULL != stmt_->get_limit_expr() || NULL != stmt_->get_limit_percent_expr()) ) {
      if (stmt_->is_fetch_with_ties()) {
        DATA_PRINTF(" with ties");
      } else {
        DATA_PRINTF(" only");
      }
    }

  }
  return ret;
}

int ObDMLStmtPrinter::print_returning()
{
  int ret = OB_SUCCESS;
  CK (OB_NOT_NULL(stmt_),
      OB_NOT_NULL(buf_),
      OB_NOT_NULL(pos_));
  CK (stmt_->is_insert_stmt() || stmt_->is_update_stmt() || stmt_->is_delete_stmt());
  if (OB_SUCC(ret)) {
    const ObDelUpdStmt &dml_stmt = static_cast<const ObDelUpdStmt&>(*stmt_);
    const ObIArray<ObRawExpr*> &returning_exprs = dml_stmt.get_returning_exprs();
    if (returning_exprs.count() > 0) {
      DATA_PRINTF(" returning ");
      OZ (expr_printer_.do_print(returning_exprs.at(0), T_NONE_SCOPE));
      for (uint64_t i = 1; OB_SUCC(ret) && i < returning_exprs.count(); ++i) {
        DATA_PRINTF(",");
        OZ (expr_printer_.do_print(returning_exprs.at(i), T_NONE_SCOPE));
      }
    }
  }
  return ret;
}

int ObDMLStmtPrinter::print_subquery(const ObSelectStmt *subselect_stmt,
                                     uint64_t subquery_print_params)
{
  int ret = OB_SUCCESS;
  ObSelectStmtPrinter printer(buf_, buf_len_, pos_,
                              subselect_stmt,
                              schema_guard_,
                              print_params_,
                              subquery_print_params & FORCE_COL_ALIAS);
  if (!(subquery_print_params & PRINT_CTE)){
    printer.disable_print_cte();
  }
  if (subquery_print_params & PRINT_BRACKET) {
    DATA_PRINTF("(");
  }
  if (OB_FAIL(printer.do_print())) {
    LOG_WARN("failed to print sub select printer", K(ret));
  }
  if (subquery_print_params & PRINT_BRACKET) {
    DATA_PRINTF(")");
  }
  return ret;
}

int ObDMLStmtPrinter::print_cte_define()
{
  int ret = OB_SUCCESS;
  ObSEArray<ObDMLStmt::TempTableInfo, 8> temp_table_infos;
  if (print_params_.print_origin_stmt_) {
    //do nothing
  } else if (OB_ISNULL(stmt_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpect null stmt", K(ret));
  } else if (OB_FAIL(const_cast<ObDMLStmt*>(stmt_)->collect_temp_table_infos(temp_table_infos))) {
    LOG_WARN("failed to collect temp table infos", K(ret));
  } else if (temp_table_infos.empty()) {
    //do nothing
  } else {
    DATA_PRINTF(is_oracle_mode() ? "WITH " : "WITH RECURSIVE ");
    for(int64_t i = 0; OB_SUCC(ret) && i < temp_table_infos.count(); ++i) {
      if (temp_table_infos.at(i).table_items_.empty()) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("the cte tableitem can not be empty", K(ret));
      } else {
        TableItem *cte_table = temp_table_infos.at(i).table_items_.at(0);
        if (OB_ISNULL(cte_table)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpect null table item", K(ret));
        } else if (OB_FAIL(print_cte_define_title(cte_table))) {
          LOG_WARN("print column name failed", K(ret));
        } else if (OB_FAIL(print_subquery(cte_table->ref_query_, PRINT_BRACKET))) {
          LOG_WARN("print table failed", K(ret));
        } else if (OB_FAIL(print_search_and_cycle(cte_table->ref_query_))) {
          LOG_WARN("print search and cycle failed", K(ret));
        }
      }
      //打印尾巴
      if (OB_FAIL(ret)) {
        //do nothing
      } else if (i == temp_table_infos.count() - 1) {
        DATA_PRINTF(" ");
      } else {
        DATA_PRINTF(", ");
      }
    }
  }
  return ret;
}


int ObDMLStmtPrinter::print_cte_define_title(TableItem* cte_table)
{
  int ret = OB_SUCCESS;
  //递归cte一定是定义了别名列表的
  //打印cte的表一定不要打印库名?
  //DATA_PRINTF(" %.*s)", LEN_AND_PTR(cte_table->table_name_));
  //cte在mysql中定义和使用是，不允许类似 db.cte_name这种使用方法，打印的时候我们
  //不能打印database name
  ObSelectStmt *sub_select_stmt = NULL;
  if (OB_ISNULL(cte_table) || OB_ISNULL(sub_select_stmt = cte_table->ref_query_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpect null params", K(ret));
  } else {
    PRINT_TABLE_NAME(print_params_, cte_table);
  }
  if (OB_SUCC(ret) && OB_NOT_NULL(cte_table->node_) && OB_NOT_NULL(cte_table->node_->children_[1])) {
    DATA_PRINTF("(");
    const ObIArray<SelectItem> &sub_select_items = sub_select_stmt->get_select_items();
    //打印列
    for (int64_t i = 0; i < sub_select_items.count() && OB_SUCC(ret); ++i) {
      if (T_CTE_SEARCH_COLUMN == sub_select_items.at(i).expr_->get_expr_type()
          || T_CTE_CYCLE_COLUMN == sub_select_items.at(i).expr_->get_expr_type()) {
        //伪列不需要打印出来
      } else {
        PRINT_QUOT;
        DATA_PRINTF("%.*s", LEN_AND_PTR(sub_select_items.at(i).alias_name_));
        PRINT_QUOT;
        if (i != sub_select_items.count() - 1
            && T_CTE_SEARCH_COLUMN != sub_select_items.at(i+1).expr_->get_expr_type()
            && T_CTE_CYCLE_COLUMN != sub_select_items.at(i+1).expr_->get_expr_type()) {
          DATA_PRINTF(", ");
        }
      }
    }
    DATA_PRINTF(")");
  }
  if (OB_SUCC(ret)) {
    DATA_PRINTF(" as ");
  }
  return ret;
}

int ObDMLStmtPrinter::print_cte_define_title(const ObSelectStmt *sub_select_stmt)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(sub_select_stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpect null params", K(ret));
  } else {
    DATA_PRINTF("(");
    const ObIArray<SelectItem> &sub_select_items = sub_select_stmt->get_select_items();
    //打印列
    for (int64_t i = 0; i < sub_select_items.count() && OB_SUCC(ret); ++i) {
      if (T_CTE_SEARCH_COLUMN == sub_select_items.at(i).expr_->get_expr_type()
          || T_CTE_CYCLE_COLUMN == sub_select_items.at(i).expr_->get_expr_type()) {
        //伪列不需要打印出来
      } else {
        PRINT_COLUMN_NAME(sub_select_items.at(i).alias_name_);
        if (i != sub_select_items.count() - 1
            && T_CTE_SEARCH_COLUMN != sub_select_items.at(i+1).expr_->get_expr_type()
            && T_CTE_CYCLE_COLUMN != sub_select_items.at(i+1).expr_->get_expr_type()) {
          DATA_PRINTF(", ");
        }
      }
    }
    DATA_PRINTF(") as ");
  }
  return ret;
}

int ObDMLStmtPrinter::print_search_and_cycle(const ObSelectStmt *sub_select_stmt)
{
  int ret = OB_SUCCESS;
  ObArenaAllocator allocator("PrintSelectStmt");
  if (OB_ISNULL(sub_select_stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("the cte table must have ref sub query", K(ret));
  } else {
    const ObIArray<SelectItem> &sub_select_items = sub_select_stmt->get_select_items();
    const ObIArray<OrderItem> &search_items = sub_select_stmt->get_search_by_items();
    if (!search_items.empty()) {
      DATA_PRINTF(" search ");
      if (sub_select_stmt->is_breadth_search()) {
        DATA_PRINTF("breadth first by ");
      } else {
        DATA_PRINTF("depth first by ");
      }
    }

    for (int64_t i = 0; i < search_items.count() && OB_SUCC(ret); ++i) {
      allocator.reuse();
      ObString column_name = ((ObColumnRefRawExpr*)(search_items.at(i).expr_))->get_column_name();
      CONVERT_CHARSET_FOR_RPINT(allocator, column_name);
      PRINT_COLUMN_NAME(column_name);
      if (lib::is_mysql_mode()) {
        if (is_descending_direction(search_items.at(i).order_type_)) {
          DATA_PRINTF("DESC ");
        }
      } else if (search_items.at(i).order_type_ == NULLS_FIRST_ASC) {
        DATA_PRINTF("ASC NULLS FIRST ");
      } else if (search_items.at(i).order_type_ == NULLS_LAST_ASC) {//use default value
        /*do nothing*/
      } else if (search_items.at(i).order_type_ == NULLS_FIRST_DESC) {//use default value
        DATA_PRINTF("DESC ");
      } else if (search_items.at(i).order_type_== NULLS_LAST_DESC) {
        DATA_PRINTF("DESC NULLS LAST ");
      }
      if (i != search_items.count() - 1) {
        DATA_PRINTF(", ");
      } else {
        DATA_PRINTF(" ");
      }
    }

    for (int64_t i = 0; i < sub_select_items.count() && OB_SUCC(ret); ++i) {
      if (T_CTE_SEARCH_COLUMN == sub_select_items.at(i).expr_->get_expr_type()) {
        DATA_PRINTF("set ");
        PRINT_COLUMN_NAME(sub_select_items.at(i).alias_name_);
      }
    }

    const ObIArray<ColumnItem> &cycle_items = sub_select_stmt->get_cycle_items();
    if (!cycle_items.empty()) {
      DATA_PRINTF("cycle ");
    }

    for (int64_t i = 0; i < cycle_items.count() && OB_SUCC(ret); ++i) {
      allocator.reuse();
      ObString column_name = ((ObColumnRefRawExpr*)(cycle_items.at(i).expr_))->get_column_name();
      CONVERT_CHARSET_FOR_RPINT(allocator, column_name);
      PRINT_COLUMN_NAME(column_name);
      if (i != cycle_items.count() - 1) {
        DATA_PRINTF(", ");
      } else {
        DATA_PRINTF(" ");
      }
    }

    for (int64_t i = 0; i < sub_select_items.count() && OB_SUCC(ret); ++i) {
      if (T_CTE_CYCLE_COLUMN == sub_select_items.at(i).expr_->get_expr_type()) {
        ObRawExpr *v;
        ObRawExpr *d_v;
        DATA_PRINTF("set ");
        PRINT_COLUMN_NAME(sub_select_items.at(i).alias_name_);
        DATA_PRINTF("to ");
        ((ObPseudoColumnRawExpr*)(sub_select_items.at(i).expr_))->get_cte_cycle_value(v, d_v);
        if (OB_ISNULL(v)
            || OB_ISNULL(d_v)
            || !v->is_const_raw_expr()
            || !d_v->is_const_raw_expr()) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("Unexpected const expr", K(ret), KPC(v), KPC(d_v));
        } else {
          ObObj non_cycle_vale = ((ObConstRawExpr*)v)->get_value();
          ObObj cycle_vale = ((ObConstRawExpr*)d_v)->get_value();
          DATA_PRINTF("'%.*s' ", LEN_AND_PTR(non_cycle_vale.get_string()));
          DATA_PRINTF("default ");
          DATA_PRINTF("'%.*s' ", LEN_AND_PTR(cycle_vale.get_string()));
        }
      }
    }
  }
  return ret;
}


//把cte的定义完整的恢复出来
int ObDMLStmtPrinter::print_with()
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(stmt_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpect null stmt", K(ret));
  } else if (!print_params_.print_origin_stmt_) {
    //do nothing
  } else if (stmt_->get_cte_definition_size() == 0) {
      // don't print
  } else {
    const ObIArray<TableItem *> &cte_tables = stmt_->get_cte_definitions();
    DATA_PRINTF(is_oracle_mode() ? "WITH " : "WITH RECURSIVE ");
    //恢复定义，cte先放本stmt中T_WITH_CLAUSE产生的的cte，再放parent放过来的
    for (int64_t i = 0; OB_SUCC(ret) && i < cte_tables.count() && OB_SUCC(ret); i++) {
      TableItem* cte_table = cte_tables.at(i);
      //打印定义
      if (OB_ISNULL(cte_table)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("the cte tableitem can not be null", K(ret));
      } else if (TableItem::NORMAL_CTE == cte_table->cte_type_
                || TableItem::RECURSIVE_CTE == cte_table->cte_type_) {
        if (OB_FAIL(print_cte_define_title(cte_table))) {
          LOG_WARN("print column name failed", K(ret));
        } else if (OB_FAIL(print_subquery(cte_table->ref_query_, PRINT_BRACKET | FORCE_COL_ALIAS))) {
          LOG_WARN("print table failed", K(ret));
        } else if (OB_FAIL(print_search_and_cycle(cte_table->ref_query_))) {
          LOG_WARN("print search and cycle failed", K(ret));
        }
      } else {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unexpected cte type", K(ret), K(cte_table->cte_type_));
      }
      //打印尾巴
      if (OB_FAIL(ret)) {
        //do nothing
      } else if (i == cte_tables.count() - 1) {
        DATA_PRINTF(" ");
      } else {
        DATA_PRINTF(", ");
      }
    }
  }
  return ret;
}

} //end of namespace sql
} //end of namespace oceanbase



